#include <pic.h>
#include <idt.h>
#include <vga.h>
#include <mm.h>
#include <sched.h>
#include <gdt.h>
#include <debug.h>
#include <loader.h>
#include <syscalls.h>
#include <i386.h>
#include <isr.h>
#include <string.h>
#include <serial.h>
#include <device.h>
#include <con.h>
#include <fs.h>
#include <hdd.h>
#include <keyboard.h>

extern void* _end;

extern pso_file task_task0_pso;
extern pso_file task_task1_pso;
extern pso_file task_task2_pso;
extern pso_file task_task3_pso;
extern pso_file task_task4_pso;
extern pso_file task_task5_pso;
extern pso_file task_task6_pso;
extern pso_file task_consola_pso;
extern pso_file task_krypto_pso;
extern pso_file task_krypto2_pso;

extern pid current_pid;

extern void task_isr();
extern void syscall_isr(); 
extern void timer_isr(); 
extern void spurious_isr(); 
extern void keyboard_isr(); 
extern void page_fault_isr(); 

void hangme(int i) {
	if ( i > 0 )
		hangme(i-1);
	_syscall();
	cli();
	hlt();
}
	
/* Entry-point del modo protegido luego de cargar los registros de
 * segmento y armar un stack */
void kernel_init(void) {

	//inicializo la gdt
	gdt_init();

	//iniacilizo el sistema de pagincacion
	mm_init();
 
 	//inicializo el sistema de interrupciones
	idt_init();

	//seteo todos los controladores de int en modo debug
	debug_init();

	//activo paginacion
	mm_page *dir;
	uint_32 cr0, cr3;

	dir = mm_dir_new();
	if (!dir) {
		vga_printf(USE_CURSOR, USE_CURSOR, "NO SE PUDO ACTIVAR PAGINACION!\n", VGA_FC_WHITE);
		while(1);
	}

	//cargo el directorio de pagina en cr3
	cr3 = rcr3();
	cr3 = (uint_32) dir;
	lcr3(cr3);

	//activo paginacion
	cr0 = rcr0();
	cr0 |= CR0_PG;
	lcr0(cr0);

	//inicializo el scheduler
	sched_init();

	//inicializo el loader
	loader_init();

	//agrego la idle task
	loader_load(&task_task0_pso, 0);

	//cargo la consola
	loader_load(&task_consola_pso, 3);
	//~ loader_load(&task_task5_pso, 3);
	//~ loader_load(&task_task6_pso, 3);
	//loader_load(&task_task3_pso, 3);
	//~ loader_load(&task_krypto_pso, 3);
	//~ loader_load(&task_krypto2_pso, 3);
	
	//registro las syscalls
	idt_register(0x30, syscall_isr, 3);

 	//registro la runtina de atencion de clock para que cambie entre las tareas
	idt_register(0x20, task_isr, 0);
	
	idt_register(0x27, spurious_isr, 0);
	idt_register(0x21, keyboard_isr, 0);

	// registro la controladora de teclado de la consola
	keyboard_init();
	keyboard_register(con_key_press);

	//inicializo el sistema de dispositivos
	fs_init();

	idt_register(0x0e, page_fault_isr, 0);
	
	//activo las interrupciones :)
	sti();

	while(1)
		if ( timer_ticks > 0 )
			//breakpoint();
			hlt();

	return;
}
